package vn.fpt.fsoft.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import vn.fpt.fsoft.dao.UserDAO;
import vn.fpt.fsoft.entity.User;

@WebServlet("/UserController")
public class UserController extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static UserDAO dao = new UserDAO();
    
    public UserController() {
        super();
    }
    
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
    }
    
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        String action = request.getParameter("action");
        
        if (action != null) {
            if ("add".equals(action)) {
                // Create new User
                addUser(request, response);
            } else if ("update".equals(action)) {
                // Amend User
                amendUser(request, response);
            } else if ("active".equals(action)) {
                // Make an in-active User active
                makeActiveUser(request, response);
                listUser(request, response);
            } else if ("getUser".equals(action)) {
                // get info of 1 user -> show in amend user page
                getUser(request, response);
            } else if ("listUser".equals(action)) {
                // List User, filter, show active/in-active user
                listUser(request, response);
            } else if ("logout".equals(action)) {
                // List User, filter, show active/in-active user
                logout(request, response);
            } else if ("login".equals(action)) {
                // login
                login(request, response);
            } else if ("retrieve".equals(action)) {
                // retrieve password
                retrievePassword(request, response);
            }
        }
    }
    
    /**
     * @param request
     * @param response
     * @throws IOException
     */
    private void logout(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        request.getSession().removeAttribute("user");
        response.getWriter().write("Success");
    }
    
    /**
     * @param request
     * @param response
     * @throws IOException
     * @throws ServletException
     */
    private void retrievePassword(HttpServletRequest request,
            HttpServletResponse response) throws IOException, ServletException {
        UserDAO dao = new UserDAO();
        String username = request.getParameter("username");
        String email = request.getParameter("email");
        
        User user = dao.getUserByUsername(username);
        if (user != null && email.equals(user.getEmail())) {
            // make a new password
            String newPassword = generateString(8);
            String newMD5Password = MD5(newPassword);
            // save the new password
            user.setPassword(newMD5Password);
            
            if (dao.updateUser(user)) {
                String result = "Your new password is: \"" + newPassword + "\"";
                response.getWriter().write(result);
            }
            
        } else {
            String result = "Username or Email is not valid.";
            response.getWriter().write(result);
        }
    }
    
    /**
     * @param request
     * @param response
     * @throws IOException
     * @throws ServletException
     */
    private void login(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        UserDAO dao = new UserDAO();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        password = MD5(password);
        
        User user = dao.getUserByUsername(username);
        if (user != null && password.equals(user.getPassword())) {
            //if user is valid
            if (user.isActive()) {
                // if user is active
                request.getSession().setAttribute("user", user);
                response.getWriter().write("Success");
            } else {
                // user is in-active
                response.getWriter().write("Your account is in-active!");
            }
        } else {
            // username or password is in-valid
            response.getWriter().write("Username or Password is not valid!");
        }
    }
    
    /**
     * @param request
     * @param response
     * @throws IOException
     */
    private void addUser(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        
        String message = "";
        List<User> listUser = new ArrayList<User>();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //Encript password
        password = MD5(password);
        String email = request.getParameter("email");
        int role = request.getParameter("role").equals("1") ? 1 : 0;
        boolean isActive = "true".equals(request.getParameter("isActive")) ? true : false;
        
        if (dao.getUserByUsername(username) != null) {
            // if the username is existed
            message = "Username \"" + username + "\" is existed";
        } else if (dao.getUserByEmail(email) != null) {
            // if the email is exitsted
            message = "Email is already registry a user";
        } else {
            // Create new user object
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            user.setEmail(email);
            user.setRole(role);
            user.setActive(isActive);
            
            if (dao.addUser(user)) {
                // if save new user success, remove session
                listUser = dao.getAllUser();
                request.getSession().setAttribute("listUser", listUser);
                request.getSession().setAttribute("currentListUser", listUser);
                message = "Create Success!";
            } else {
                message = "Fail";
            }
        }
        response.getWriter().write(message);
        return;
    }
    
    /**
     * @param request
     * @param response
     * @throws IOException
     */
    private void amendUser(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String message = "";
        
        int userID = Integer.parseInt(request.getParameter("userID"));
        String email = request.getParameter("email");
        int role = request.getParameter("role").equals("1") ? 1 : 0;
        boolean isActive = "true".equals(request.getParameter("isActive")) ? true : false;
        
        User userWithEmail = dao.getUserByEmail(email);
        if ((userWithEmail != null) && (userWithEmail.getUserID() != userID)) {
            // if the email is alredy registry another user
            message = "Email is already registry a user: "
                    + userWithEmail.getUserID() + userID;
        } else {
            User user = dao.getUserByUserID(userID);
            user.setEmail(email);
            user.setRole(role);
            user.setActive(isActive);
            
            if (dao.updateUser(user)) {
                // if success, remove session
                List<User> listUser = new ArrayList<User>();
                listUser = dao.getAllUser();
                request.getSession().setAttribute("listUser", listUser);
                request.getSession().setAttribute("currentListUser", listUser);
                message = "Update Success!";
            } else {
                message = "Fail";
            }
        }
        response.getWriter().write(message);
        return;
    }
    
    /**
     * @param request
     * @param response
     * @throws IOException
     */
    private void makeActiveUser(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        int userID = Integer.parseInt(request.getParameter("userID"));
        
        // get the user with defined userid
        User user = dao.getUserByUserID(userID);
        user.setActive(true);
        
        if (dao.updateUser(user)) {
            // if success, remove session -> list
            request.getSession().removeAttribute("listUser");
            request.getSession().removeAttribute("currentListUser");
        }
    }
    
    
    /**
     * @param request
     * @param response
     * @throws IOException
     */
    /**
     * @param request
     * @param response
     * @throws IOException
     */
    private void getUser(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        int userID = Integer.parseInt(request.getParameter("userID"));
        User user = dao.getUserByUserID(userID);
        
        if (user != null) {
            String result = "";
            result += "<tr style=\"height: 40px;\">";
            result += "<td width=\"206\">Username:</td>";
            result += "<td width=\"481\"><input id=\"username\" type=\"text\" size=\"30\" disabled value=\""
                    + user.getUsername() + "\"/></select></td></tr>";
            result += "<tr style=\"height: 40px;\">";
            result += "<td width=\"206\">Password:</td>";
            result += "<td width=\"481\"><input id=\"password\" type=\"text\" size=\"30\" disabled value=\""
                    + user.getPassword() + "\"/></select></td></tr>";
            result += "<tr style=\"height: 40px;\">";
            result += "<td width=\"206\">Email:</td>";
            result += "<td width=\"481\"><input id=\"email\" type=\"text\" size=\"30\" value=\""
                    + user.getEmail() + "\"/></select></td></tr>";
            result += "<tr style=\"height: 40px;\">";
            result += "<td width=\"206\">Role:</td>";
            result += "<td width=\"481\"><select id=\"role\" style=\"width: 25%; height: 20px;\">";
            if (user.getRole() == 1) {
                result += "<option value=\"0\">User</option>";
                result += "<option value=\"1\" selected=\"selected\">Admin</option></select></td></tr>";
            } else {
                result += "<option value=\"0\" selected=\"selected\">User</option>";
                result += "<option value=\"1\">Admin</option></select></td></tr>";
            }
            result += "<tr style=\"height: 40px;\">";
            result += "<td>Is Active: </td>";
            if (user.isActive()) {
                result += "<td><input id=\"isactive\" type=\"checkbox\" checked=\"checked\"></input></td></tr>";
            } else {
                result += "<td><input id=\"isactive\" type=\"checkbox\"></input></td></tr>";
            }
            response.getWriter().write(result);
        }
        
    }
    
    /**
     * @param request
     * @param response
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
    private void listUser(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String checked = request.getParameter("checked");
        String idClick = request.getParameter("idclick");
        List<User> listUser = new ArrayList<User>();
        
        if (request.getSession().getAttribute("listUser") == null) {
            listUser = getAllUser();
            request.getSession().setAttribute("listUser", listUser);
            request.getSession().setAttribute("currentListUser", listUser);
        } else {
            listUser = (List<User>) request.getSession().getAttribute(
                    "listUser");
        }
        
        if (idClick != null) {
            // if the request is filter
            listUser = filterByName(idClick, listUser);
            request.getSession().setAttribute("currentListUser", listUser);
            // get active user
            if ("1".equals(checked) == false) {
                listUser = getActiveUser(listUser);
            }
        } else {
            // if the request is show in-active/active user
            listUser = (List<User>) request.getSession().getAttribute(
                    "currentListUser");
            if ("1".equals(checked) == false) {
                listUser = getActiveUser(listUser);
            }
        }
        
        if (listUser != null) {
            int length = listUser.size();
            String result = "<table cellspacing=1 class=tablesorter id = table>";
            result += "<thead>";
            result += "<tr>";
            result += "<th>Username</th>";
            result += "<th>Password</th>";
            result += "<th>Email</th>";
            result += "<th>Role</th>";
            result += "<th>is Active</th>";
            result += "</tr>";
            result += "</thead>";
            result += "<tbody>";
            for (int i = 0; i < length; i++) {
                result += "<tr onclick=Click_Record("
                        + listUser.get(i).getUserID() + ","
                        + listUser.get(i).isActive() + ");>";
                result += "<td>" + listUser.get(i).getUsername() + "</td>";
                result += "<td>" + listUser.get(i).getPassword() + "</td>";
                result += "<td>" + listUser.get(i).getEmail() + "</td>";
                if (listUser.get(i).getRole() == 1) {
                    result += "<td>Admin</td>";
                } else {
                    result += "<td>User</td>";
                }
                if (listUser.get(i).isActive()) {
                    result += "<td>Yes</td>";
                } else {
                    result += "<td>No</td>";
                }
                result += "</tr>";
            }
            result += "</tbody>";
            result += "</table>";
            result += "<div id=pager class=pager style=right:5px;float:right;>";
            result += "<form>";
            result += "<img src=img/first.png class=first />";
            result += "<img src=img/prev.png class=prev />";
            result += " <input type=text class=pagedisplay size=5 style=width:63px;height:20px;/>";
            result += "<img src=img/next.png class=next />";
            result += "<img src=img/last.png class=last />";
            result += "<select class=pagesize style=visibility:hidden;>";
            result += "<option selected=selected  value=15></option>";
            result += "</select>";
            result += "</form>";
            result += "</div>";
            response.getWriter().write(result);
        }
    }
    
    private List<User> getAllUser() {
        return dao.getAllUser();
    }
    
    /**
     * @param listUser
     * @return
     */
    private List<User> getActiveUser(List<User> listUser) {
        List<User> result = new ArrayList<User>();
        for (User u : listUser) {
            if (u.isActive()) {
                result.add(u);
            }
        }
        return result;
    }
    
    /**
     * @param key
     * @param listUser
     * @return
     */
    private List<User> filterByName(String key, List<User> listUser) {
        List<User> result = new ArrayList<User>();
        char letter;
        
        if ("all".equals(key)) {
            return listUser;
        } else if ("digital".equals(key)) {
            for (User u : listUser) {
                if (Character.isDigit(u.getUsername().charAt(0))) {
                    result.add(u);
                }
            }
        } else if ("ae".equals(key)) {
            for (User u : listUser) {
                letter = Character.toLowerCase(u.getUsername().charAt(0));
                if (('a' <= letter) && (letter <= 'e')) {
                    result.add(u);
                }
            }
        } else if ("fj".equals(key)) {
            for (User u : listUser) {
                letter = Character.toLowerCase(u.getUsername().charAt(0));
                if (('f' <= letter) && (letter <= 'j')) {
                    result.add(u);
                }
            }
        } else if ("kn".equals(key)) {
            for (User u : listUser) {
                letter = Character.toLowerCase(u.getUsername().charAt(0));
                if (('k' <= letter) && (letter <= 'n')) {
                    result.add(u);
                }
            }
        } else if ("or".equals(key)) {
            for (User u : listUser) {
                letter = Character.toLowerCase(u.getUsername().charAt(0));
                if (('o' <= letter) && (letter <= 'r')) {
                    result.add(u);
                }
            }
        } else if ("sv".equals(key)) {
            for (User u : listUser) {
                letter = Character.toLowerCase(u.getUsername().charAt(0));
                if (('s' <= letter) && (letter <= 'v')) {
                    result.add(u);
                }
            }
        } else if ("wz".equals(key)) {
            for (User u : listUser) {
                letter = Character.toLowerCase(u.getUsername().charAt(0));
                if (('w' <= letter) && (letter <= 'z')) {
                    result.add(u);
                }
            }
        }
        return result;
    }
    
    /**
     * @param string
     * @return String
     */
    private String MD5(String password) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest
                    .getInstance("MD5");
            byte[] array = md.digest(password.getBytes());
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < array.length; ++i) {
                sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100)
                        .substring(1, 3));
            }
            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * @param md5
     * @return String
     */
    public static String generateString(int length) {
        Random rd = new Random();
        String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
        char[] text = new char[length];
        for (int i = 0; i < length; i++) {
            text[i] = characters.charAt(rd.nextInt(characters.length()));
        }
        return new String(text);
    }
}